package com.powersi.hygeia.framework.jdbclogger;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.logging.Logger;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.powersi.hygeia.framework.jdbclogger.formatters.BlobParameterFormatterImpl;
import com.powersi.hygeia.framework.jdbclogger.formatters.BytesParameterFormatterImpl;
import com.powersi.hygeia.framework.util.LogHelper;

/**
 * The Class JdbcLoggerDriver.
 */
public class JdbcLoggerDriver extends AbstractWrapperDriver {
	/** The log. */
	private static Log log = LogFactory.getLog(LogHelper
			.getLoggerName(AbstractWrapperDriver.class));
	private static final String DRIVER_NAME = "oracle.jdbc.driver.OracleDriver";
	private static final String WRAPPER_DRIVER_NAME = "com.powersi.hygeia.framework.jdbclogger.oracle10g.OracleDriverWrapper";
	static {
		JdbcLoggerConfig.setJDBCLoggerDriverFlag(true);

		// register the wrapper driver
		String wrapperDriverClassName = registerWrapperForName(DRIVER_NAME);
		log.info("Wrapper '" + wrapperDriverClassName
				+ "' successfully registed for driver '" + DRIVER_NAME + "'");
	}

	/**
	 * Instantiates a new jdbc logger driver.
	 */
	public JdbcLoggerDriver() {
		super();
		this.formatters.add(new BlobParameterFormatterImpl());
		this.formatters.add(new BytesParameterFormatterImpl());
	}

	/**
	 * Replaces the given driver class name with the corresponding wrapper one,
	 * in the DriverManager.
	 * 
	 * @param userDriverClassName
	 *            the driver class to be replace with the corresponding wrapper
	 *            driver.
	 * 
	 * @return the wrapper driver class name that replace the given user driver
	 *         class name.
	 */
	private static String registerWrapperForName(String userDriverClassName) {
		String wrapperDriverClassName = null;

		try {
			// look in the classpath for a custom driver that supports the
			// requested driver
			Driver userDriver = findRegisteredUserDriver(userDriverClassName);

			if (userDriver == null) {
				// there is no registered user driver, try registering it now
				try {
					Class.forName(userDriverClassName);
					// try again, getting the instance from the driver manager
					userDriver = findRegisteredUserDriver(userDriverClassName);
				} catch (ClassNotFoundException exc) {
					// ignore, we failed to initialize the user driver
				}
			}

			if (userDriver != null) {
				AbstractWrapperDriver wrapperDriver = (AbstractWrapperDriver) Class
						.forName(WRAPPER_DRIVER_NAME).newInstance();
				wrapperDriverClassName = wrapperDriver.getClass().getName();

				wrapperDriver.setDriver(userDriver);

				DriverManager.deregisterDriver(userDriver);
				DriverManager.registerDriver(wrapperDriver);
			} else {
				log.fatal("Could not find user driver '" + userDriverClassName
						+ "' in the DriverManager.");
			}
		} catch (Exception exc) {
			log.error("Exception while registering driver.", exc);
		}

		return wrapperDriverClassName;
	}

	/**
	 * Find registered user driver.
	 * 
	 * @param userDriverClassName
	 *            the user driver class name
	 * @return the driver
	 */
	public static Driver findRegisteredUserDriver(String userDriverClassName) {
		Enumeration en = DriverManager.getDrivers();
		while (en.hasMoreElements()) {
			Driver aDriver = (Driver) en.nextElement();
			if (aDriver.getClass().getName().equals(userDriverClassName)) {
				return aDriver;
			}
		}

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.powersi.hygeia.framework.jdbclogger.AbstractWrapperDriver#connect
	 * (java.lang.String, java.util.Properties)
	 */
	@Override
	public Connection connect(String url, Properties properties)
			throws SQLException {
		if (getDriver() == null)
			return null;

		// has to return null if no connection available for compliance with the
		// JDBC API
		Connection con = getDriver().connect(url, properties);
		if (con != null)
			return new ConnectionWrapper(con, formatters);

		return null;
	}

	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		// TODO Auto-generated method stub
		return null;
	}
}
